#include "ET++.ph"
#include "Converter.h"

#include "Class.h"
#include "Bitmap.h"
#include "String.h"
#include "Data.h"
#include "System.h"
#include "TypeMatcher.h"
#include "ClassManager.h"
#include "ET_stdio.h"

#include "et.xpm3"
static SmartBitmap gETIcon(et);
		
Converter *gEtConverter;

//---- ETFileTypeMatcher -------------------------------------------------------

class ETFileTypeMatcher: public TypeMatcher {
public:
	ETFileTypeMatcher() : TypeMatcher(cDocTypeET, "et", (char*) cMagic, FALSE)
		{ }
	bool MatchContents(Data*, const char *buf, int);
	Bitmap *GetBitmap()
		{ return gETIcon; }
};

static ETFileTypeMatcher et_matcher;
TypeMatcher *gEtMatcher= &et_matcher;

bool ETFileTypeMatcher::MatchContents(Data *data, const char *buf, int l)
{
	if (TypeMatcher::MatchContents(data, buf, l)) {
		char ettype[100], crea[100];
		char *p= strsave(&buf[strlen(cMagic)]);
		int rc= sscanf(p, "%s %s", ettype, crea);
		delete p;
		if (rc == 2) {
			Class *cla= gClassManager->Find(ettype);
			if (cla)
				data->SetClassType(cla);
			data->SetType(Symbol(ettype));
			data->SetCreator(Symbol(crea));
			return TRUE;
		}
	}
	return FALSE;
}

//---- EtConverter ------------------------------------------------------------

class EtConverter : public Converter {
public:
	MetaDef(EtConverter);
	EtConverter()
		{ }
	const char *AsString()
		{ return "ET++ Object Input/Output"; }
	void InitNew()
		{ Converter::InitNew(); gEtConverter= this; }
	Object *Convert(Data *data, Class *want);
	bool CanConvert(Data *data, Class *want);
	bool CanConvertTo(Object*)
		{ return TRUE; }
	bool ConvertTo(Data *data, Object *op);
};

NewMetaImpl0(EtConverter, Converter);

bool EtConverter::CanConvert(Data *data, Class *want)
{
	if (!data->IsETFormat())
		return FALSE;
	if (gDebug)
		fprintf(stderr, "EtConverter::CanConvert: is:%s want:%s\n",
									data->Type().AsString(), want->Name());
	if (data->GetClassType() == 0) {
		if (data->Type() == Symbol(want->Name()))
			return TRUE;
		if (data->IsETFormat()) {
			Object *op= Convert(data, want);
			if (op == 0)
				return FALSE;
			SafeDelete(op);
			return TRUE;
		}
		return FALSE;
	}
	//fprintf(stderr, "%s\n", data->GetClassType()->Name());
	//if (!data->IsETFormat())
	//    return FALSE;
	//fprintf(stderr, "oops\n");
	return data->GetClassType()->isKindOf(want);
}

Object *EtConverter::Convert(Data *data, Class *want)
{
	StreamBuf *sb= data->GetStreamBufForReading();
	IStream ois(sb, 0, TRUE);
	Object *op= 0;
	char c;

	ois.get(c);
	if (c == '@') {
		while (ois.get(c))
			if (c == '\n')
				break;
	} else
		ois.putback(c);

	ois >> op;
	if (op && op->IsA()->isKindOf(want))
		return op;
	SafeDelete(op);
	return 0;
}

bool EtConverter::ConvertTo(Data *data, Object *op)
{
	OStream ois(data->GetStreamBufForWriting(), TRUE);
	ois << cMagic SP << op->ClassName() SP << BaseName(gProgname) NL;
	ois << op NL;
	return TRUE;
}

